package com.portal.framework.util;


import java.beans.PropertyDescriptor;
import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import ognl.NullHandler;
import ognl.Ognl;
import ognl.OgnlException;
import ognl.OgnlRuntime;

import org.apache.commons.lang.ClassUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

//import com.opensymphony.xwork.util.OgnlUtil;

/**
 */
public class ClassUtil {

	private static Class[][] PRIMARY = { { Boolean.class, Boolean.TYPE },
			{ Byte.class, Byte.TYPE }, { Character.class, Character.TYPE },
			{ Short.class, Short.TYPE }, { Integer.class, Integer.TYPE },
			{ Long.class, Long.TYPE }, { Float.class, Float.TYPE },
			{ Double.class, Double.TYPE }, { Void.class, Void.TYPE } };

	public static Class forName(String name) throws ClassNotFoundException {
		return getClassLoader().loadClass(name);
	}

	public static ClassLoader getClassLoader() {
		return Thread.currentThread().getContextClassLoader();
	}

	public static Class toMainClass(Class cls) {
		if (cls != null && cls.isPrimitive()) {
			for (Class[] pc : PRIMARY) {
				if (pc[1] == cls)
					return pc[0];
			}
		}
		return cls;
	}

	public static Class toPrimaryClass(Class cls) {
		if (cls == null)
			return cls;
		if (cls.isPrimitive())
			return cls;
		for (Class[] pc : PRIMARY) {
			if (pc[0] == cls)
				return pc[1];
		}
		return cls;
	}

	public static boolean isMainClass(Class cls) {
		for (Class[] pc : PRIMARY) {
			if (pc[1] == cls || pc[0] == cls)
				return true;
		}
		if (cls == String.class) {
			return true;
		}

		return false;
	}

	public static boolean isAssignFrom(Class[] cls, Class[] from) {
		if (cls == null || cls.length == 0) {
			if (from == null || from.length == 0) {
				return true;
			}
		}

		if (cls.length != from.length)
			return false;

		for (int i = 0; i < cls.length; i++) {
			if (!isAssignFrom(cls[i], from[i]))
				return false;
		}
		return true;
	}

	public static boolean isAssignFrom(Class<?> var, Class<?> value) {
		if (var == null) {
			return value == null;
		}

		if (value == null) {
			return false;
		}

		var = toMainClass(var);
		value = toMainClass(value);
		if (var.isAssignableFrom(value))
			return true;

		return false;
	}

	public static boolean isImplementInterface(Class<?> cls,
			Class<?> interfaceClass) {
		if (cls == null || interfaceClass == null)
			return false;
		return interfaceClass.isAssignableFrom(cls);
	}

	public static boolean isExtendFrom(Class<?> cls, Class<?> from) {
		if (cls == null || from == null)
			return false;
		return from.isAssignableFrom(cls);
	}

	public static Method lookupMethod(Class cls, String name, Class returnType,
			Class[] valcls) {
		return lookupMethod(cls, name, returnType, valcls, false);
	}

	public static Method lookupMethod(Class cls, String name, Class returnType,
			Class[] valcls, boolean all) {
		Method[] ms = cls.getMethods();
		if (ms != null && ms.length > 0) {
			for (int i = 0; i < ms.length; i++) {
				if (ms[i].getName().equals(name)) {
					if (valcls != null) {
						Class[] pcs = ms[i].getParameterTypes();
						if (!isAssignFrom(pcs, valcls)) {
							continue;
						}
					}
					if (returnType != null) {
						Class rt = ms[i].getReturnType();
						if (!isAssignFrom(rt, returnType)) {
							continue;
						}
					}
					return ms[i];
				}
			}
		}

		if (all) {
			Class sup = cls.getSuperclass();
			if (sup != null) {
				return lookupMethod(sup, name, returnType, valcls, all);
			}
		}

		return null;
	}

	public static Field getLocalField(Class cls, String name, Class type) {
		Field[] fs = cls.getDeclaredFields();
		for (Field f : fs) {
			if (f.getName().equals(name)) {
				if (type == null || isExtendFrom(f.getType(), type)) {
					return f;
				}
			}
		}
		return null;
	}

	public static Field getField(Class cls, String name, Class type) {
		Field f = getLocalField(cls, name, type);
		if (f == null) {
			Class s = cls.getSuperclass();
			if (s != null)
				return getField(s, name, type);
		}
		return f;
	}

	public static Method getMethod(Class cls, String name, Class[] valcls)
			throws Exception {
		Method m = lookupMethod(cls, name, null, valcls);
		if (m != null)
			return m;
		// let's throw NoSuchMethodException
		return cls.getMethod(name, valcls);
	}

	public static String getShortName(String className) {
		if (StringUtils.empty(className)) {
			throw new IllegalArgumentException(
					"The class name must not be empty");
		}
		char[] chars = className.toCharArray();
		int lastDot = 0;
		for (int i = 0; i < chars.length; i++) {
			if (chars[i] == '.') {
				lastDot = i + 1;
			} else if (chars[i] == '$') { // handle
				// inner classes
				chars[i] = '.';
			}
		}
		return new String(chars, lastDot, chars.length - lastDot);
	}

	public static String getShortName(Class cls) {
		if (cls == null)
			return null;
		return getShortName(cls.getName());
	}

	public static Class toClass(Type type) {
		if (type instanceof Class) {
			return (Class) type;
		}
		if (type instanceof ParameterizedType) {
			return toClass(((ParameterizedType) type).getRawType());
		}
		return null;
	}

	public static String getResourceName(Class cls) {
		return getResourceName(cls, null);
	}

	public static String getResourceName(Class cls, String ext) {
		String name = cls.getName();
		name = name.replace('.', '/');
		if (ext != null)
			name += ext;
		return name;
	}

	public static String getClassPackageResourceName(Class clsPackage,
			String resourceName) {
		String name = clsPackage.getPackage().getName();
		name = name.replace('.', '/');
		return name + "/" + resourceName;
	}

	public static String[] listPackageClass(String packageName)
			throws Exception {

		String name = new String(packageName);
		if (!name.startsWith("/")) {
			// name = "/" + name;
		}

		name = name.replace('.', '/');

		// Get a File object for the package
		URL url = Thread.currentThread().getContextClassLoader().getResource(
				name);
		String path = URLDecoder.decode(url.getFile(), "UTF-8");
		File directory = new File(path);

		if (!directory.exists()) {
			return new String[0];
		}

		// Get the list of the files contained in the package
		List<String> r = new LinkedList<String>();
		String[] files = directory.list();
		for (String file : files) {
			// we are only interested in .class files
			if (file.endsWith(".class")) {
				// removes the .class extension
				String classname = file.substring(0, file.length()
						- ".class".length());
				r.add(packageName + "." + classname);
			}
		}
		return r.toArray(new String[0]);

	}

	public static URL getResource(String res) {
		return getClassLoader().getResource(res);
	}

	public static boolean isAbstract(Class cls) {
		if (cls.isInterface())
			return true;
		if (Modifier.isAbstract(cls.getModifiers()))
			return true;
		if (cls.isEnum())
			return true;
		if (cls.isAnnotation())
			return true;
		return false;
	}

	public static Object getFieldValue(Object obj, Field f) {
		if (obj == null || f == null) {
			return null;
		}
		Object ret = null;
		boolean b = f.isAccessible();
		f.setAccessible(true);
		try {
			ret = f.get(obj);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} finally {
			f.setAccessible(b);
		}

		return ret;
	}

	public static void setFieldValue(Object obj, Field f, Object value) {
		if (obj == null || f == null) {
			return;
		}
		boolean b = f.isAccessible();
		f.setAccessible(true);
		try {
			f.set(obj, value);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} finally {
			f.setAccessible(b);
		}
	}

	public static void setFieldValue(Object obj, String fieldName, Object value) {
		Field f = getField(obj.getClass(), fieldName, null);
		if (f != null) {
			setFieldValue(obj, f, value);
		}
	}

	public static <T> T getFieldValue(Object obj, String fieldName,
			Class<T> retValueType) {
		Field f = getField(obj.getClass(), fieldName, null);
		if (f == null) {
			return null;
		}

		return retValueType.cast(getFieldValue(obj, f));
	}

	public static Object getFieldValue(Object obj, String fieldName) {
		return getFieldValue(obj, fieldName, Object.class);
	}

	public static <T> T newIntance(Class<T> cls) {
		try {
			return cls.newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

	public static List<Field> getAllDeclaredFields(Class cls) {
		List<Field> allField = new ArrayList<Field>();
		List<Class> classes = ClassUtils.getAllSuperclasses(cls);
		classes.add(cls);
		if (CollectionUtils.notEmpty(classes)) {
			for (Class c : classes) {
				allField.addAll(Arrays.asList(c.getDeclaredFields()));
			}
		}
		return allField;
	}

	/**
	 * 调用一个对象的方法(强行调用,私有方法也可以调用)
	 * 
	 * @param <T>
	 *            返回类型的泛型
	 * @param targetObj
	 *            调用的对象
	 * @param methodName
	 *            调用的方法名
	 * @param retType
	 *            调用方法的返回类型
	 * @param argsTypes
	 *            调用方法的参数的类型
	 * @param args
	 *            调用访求的参数
	 * @return
	 */
	public static <T> T invokeMethodForce(Object targetObj, String methodName,
			Class<T> retType, Class[] argsTypes, Object[] args) {
		if (targetObj == null) {
			return null;
		}

		Method m = lookupMethod(targetObj.getClass(), methodName, retType,
				argsTypes, true);
		if (m == null) {
			return null;
		}

		boolean b = m.isAccessible();
		m.setAccessible(true);
		try {
			return retType.cast(m.invoke(targetObj, args));
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			m.setAccessible(b);
		}
		return null;
	}

	public static <T> T invokeMethodForce(Object targetObj, String methodName,
			Class<T> retType, Object[] args) {
		return invokeMethodForce(targetObj, methodName, retType, null, args);
	}

	public static <T> T invokeMethodForce(Object targetObj, String methodName,
			Class<T> retType) {
		return invokeMethodForce(targetObj, methodName, retType, null);
	}

	public static <T> T invokeMethodForce(Object targetObj, String methodName,
			Object[] args) {
		return invokeMethodForce(targetObj, methodName, (Class<T>) null, null,
				args);
	}

	public static Object invokeMethodForce(Object targetObj, String methodName) {
		return invokeMethodForce(targetObj, methodName, Object.class);
	}

	/**
	 * 用el表达式设置一个对象的值.如果对象中有对象时,会自动创建新的对象(使用默认的构造函数进行创建对象)<BR>
	 * 用法:<BR>
	 * setFieldValueByEL('a.b.name',new A(),"¬˸��")<BR>
	 * 最后:A对象中的B会被自动创建对象,b中的name的值为¬˸��字符串
	 * 
	 * @param expression 表达式(参考ognl)
	 * @param target 要设置值的对象
	 * @param value 要进行设置的值
	 * @return
	 */
//	public static <T> T setFieldValueByEL(String expression, T target,
//			Object value) {
//		if (target == null || expression == null) {
//			return null;
//		}
//
//		OgnlRuntime.setNullHandler(Object.class, new CreateObjectNullHandler());
//		try {
//			Ognl.setValue(expression, target, value);
//		} catch (OgnlException e) {
//			e.printStackTrace();
//		}
//		return target;
//	}

//	public static void setFieldValueByEL(Map<String, Object> context,
//			Object target) {
//		if (context != null && target != null) {
//			for (String key : context.keySet()) {
//				setFieldValueByEL(key, target, context.get(key));
//			}
//		}
//	}

	/**
	 * 用el表达式得到一个对象的值<BR>
	 * 用法:<BR>
	 * A a = new A();<BR>
	 * B b = new B();<BR>
	 * b.setName("name");<BR>
	 * a.setB(b);<BR>
	 * getFieldValueByEL('a.b.name',a,String.class)<BR>
	 * 得到的值为"name"字符串
	 * 
	 * @param expression 表达式(参考ognl)
	 * @param target 要得到值的对象
	 * @param retType 要得到的值的类型
	 * @return
	 */
	public static <T> T getFieldValueByEL(String expression, Object target,
			Class<T> retType) {
		try {
			return retType.cast(Ognl.getValue(expression, target));
		} catch (OgnlException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 当要设置的值的对象为空时,自动创建新的对象
	 * 
	 * @author ¬˸��
	 * @date 2008-5-8
	 */
//	private static class CreateObjectNullHandler implements NullHandler {
//
//		private static final Log log = LogFactory
//				.getLog(CreateObjectNullHandler.class);
//
//		public Object nullMethodResult(Map context, Object target,
//				String methodName, Object[] args) {
//			return null;
//		}
//
////		public Object nullPropertyValue(Map context, Object target,
////				Object property) {
////			if ((target == null) || (property == null)) {
////				return null;
////			}
////
////			try {
////				String propName = property.toString();
////				Object realTarget = OgnlUtil.getRealTarget(propName, context,
////						target);
////				Class clazz = null;
////
////				if (realTarget != null) {
////					PropertyDescriptor pd = OgnlRuntime.getPropertyDescriptor(
////							realTarget.getClass(), propName);
////					if (pd == null) {
////						return null;
////					}
////
////					clazz = pd.getPropertyType();
////				}
////
////				if (clazz == null) {
////					return null;
////				}
////
////				Object param = createObject(clazz, realTarget, propName,
////						context);
////
////				Ognl.setValue(propName, context, realTarget, param);
////
////				return param;
////			} catch (Exception e) {
////				log.error("", e);
////			}
////
////			return null;
////		}
//
//		private Object createObject(Class clazz, Object target,
//				String property, Map context) throws Exception {
//			if (Collection.class.isAssignableFrom(clazz)) {
//				return new ArrayList();
//			} else if (clazz == Map.class) {
//				return new HashMap();
//			}
//
//			return clazz.newInstance();
//		}
//	}
	/**
	 * 根据默认构造函数创建对象
	 * 
	 * @return
	 */
	public static <T> T newIntance(Class<T> classType, String className) {
		try {
			return classType.cast(forName(className).newInstance());
		} catch (InstantiationException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}
	
	public static InputStream getResourceAsStream(String res) {
		return getClassLoader().getResourceAsStream(res);
	}
	
	public static InputStream getResourceAsStream(String res,ClassLoader classLoader) {
		if(classLoader == null){
			return getResourceAsStream(res);
		}
		return classLoader.getResourceAsStream(res);
	}
}